#include <linux/usb.h>

#define VENDOR_ID	0x0606
#define PRODUCT_ID	0x0606

static struct usb_device_id id_table[] = {
	{USB_DEVICE(VENDOR_ID, PRODUCT_ID)}, {},
};

MODULE_DEVICE_TABLE(usb, id_table);

static struct usb_device* m_udev;
static const char *types[] = {"control","isoc","bulk","int"};

static void output_altsetting(struct usb_device *udev, struct usb_host_interface *as, int index){
	int l;
	struct usb_host_endpoint *ep;
	
	if(as == 0) return;
	printk("<3>%d endpoints in altsetting %d.\n", as->desc.bNumEndpoints, index);
	for(l=0;l<as->desc.bNumEndpoints;l++){
		ep = &as->endpoint[l];
		if(ep == 0) continue;
		printk("<3>endpoint %d: direction '%s' type '%s'\n",
			l,
			(ep->desc.bEndpointAddress & USB_ENDPOINT_DIR_MASK)==USB_DIR_IN?"to host":"to device",
			types[ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK]);
	}
}

static void output_interface(struct usb_device *udev, struct usb_interface *ifp, int index){
	int k;
	
	if(ifp == 0) return;
	printk("<3>%d altsettings in interface %d.\n", ifp->num_altsetting, index);
	for(k=0;k<ifp->num_altsetting;k++)
		output_altsetting(udev, &ifp->altsetting[k], k);
}

static void output_configuration(struct usb_device *udev, struct usb_config_descriptor *cfg, int index){
	int j;

	if(cfg == 0) return;
	printk("<3>%d interfaces in configuration %d.\n", cfg->bNumInterfaces, index);
	for(j=0;j<cfg->bNumInterfaces;j++){
		output_interface(udev, udev->config[index].interface[j], j);
	}
}

int m_probe(struct usb_interface *interface, const struct usb_device_id *id){
	struct usb_device *udev=interface_to_usbdev(interface);
	int i;
	m_udev=usb_get_dev(udev);

	printk("<3>Device (Vendor %x Product %x) has %d configurations\n", 
		VENDOR_ID, 
		PRODUCT_ID,
		udev->descriptor.bNumConfigurations);

	for(i=0;i<udev->descriptor.bNumConfigurations;i++)
		output_configuration(udev, &udev->config[i].desc, i);

	return 0;
}

void m_disconnect(struct usb_interface *interface){
	usb_put_dev(m_udev);
}

struct usb_driver m_driver={
	.name = "listendpoints",
	.probe = m_probe,
	.disconnect = m_disconnect,
	.id_table = id_table,
};

int __init m_init(void)
{
	if(usb_register(&m_driver))
		return -1;
	printk("<3>module 'listendpoints' installed.\n");
	return 0;
}

void __exit m_exit(void)
{
	usb_deregister(&m_driver);
}

module_init(m_init);
module_exit(m_exit);
MODULE_LICENSE("GPL");
